diff --git a/assets/src/bundles/webapp/coverage.css b/assets/src/bundles/webapp/coverage.css new file mode 100644 index 00000000..e118a0e5 --- /dev/null +++ b/assets/src/bundles/webapp/coverage.css @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2021 The Software Heritage developers + * See the AUTHORS file at the top-level directory of this distribution + * License: GNU Affero General Public License version 3, or any later version + * See top-level LICENSE file for more information + */ + +.swh-coverage { + padding-top: 0.3rem; + border: none; + overflow: visible; +} + +.swh-coverage a { + text-decoration: none; +} + +.swh-coverage-col { + padding-left: 10px; + padding-right: 10px; +} + +.swh-coverage-header { + padding-top: 0; + padding-bottom: 0; +} + +.swh-coverage-logo { + display: block; + width: 100%; + height: 50px; + margin-left: auto; + margin-right: auto; + object-fit: contain; + + /* polyfill for old browsers, see https://github.com/bfred-it/object-fit-images */ + font-family: "object-fit: contain;"; +} + +.swh-coverage-list { + width: 100%; + height: 320px; + border: none; +} + +.swh-coverage-chevron { + position: absolute; + right: 0; +} + +.swh-coverage .card-header .mdi { + transition: 0.3s transform ease-in-out; +} + +.swh-coverage .card-header .collapsed .mdi { + transform: rotate(90deg); +} + +.swh-coverage-info-body { + max-height: 150px; + overflow-y: auto; + overflow-x: hidden; + scrollbar-width: thin; /* Firefox only */ + padding: 0; +} + +/* Thin scrollbar for chromium based browsers */ + +.swh-coverage-info-body::-webkit-scrollbar { + width: 4px; +} + +.swh-coverage-info-body::-webkit-scrollbar-track { + background: #eff0f1; +} + +.swh-coverage-info-body::-webkit-scrollbar-thumb { + background: #909396; +} diff --git a/assets/src/bundles/webapp/index.js b/assets/src/bundles/webapp/index.js index 90663d72..1189dd91 100644 --- a/assets/src/bundles/webapp/index.js +++ b/assets/src/bundles/webapp/index.js @@ -1,27 +1,28 @@ /** - * Copyright (C) 2018-2020 The Software Heritage developers + * Copyright (C) 2018-2021 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information */ // webapp entrypoint bundle centralizing global custom stylesheets // and utility js modules used in all swh-web applications // global swh-web custom stylesheets import './webapp.css'; import './breadcrumbs.css'; +import './coverage.css'; export * from './webapp-utils'; // utility js modules export * from './code-highlighting'; export * from './readme-rendering'; export * from './pdf-rendering'; export * from './notebook-rendering'; export * from './xss-filtering'; export * from './history-counters'; export * from './badges'; export * from './sentry'; export * from './math-typesetting'; export * from './status-widget'; diff --git a/assets/src/bundles/webapp/webapp.css b/assets/src/bundles/webapp/webapp.css index 06954f92..2de07c90 100644 --- a/assets/src/bundles/webapp/webapp.css +++ b/assets/src/bundles/webapp/webapp.css @@ -1,703 +1,749 @@ /** * Copyright (C) 2018-2021 The Software Heritage developers * See the AUTHORS file at the top-level directory of this distribution * License: GNU Affero General Public License version 3, or any later version * See top-level LICENSE file for more information */ html { height: 100%; overflow-x: hidden; scroll-behavior: auto !important; } body { min-height: 100%; margin: 0; position: relative; padding-bottom: 120px; } a:active, a.active { outline: none; } code { background-color: #f9f2f4; } pre code { background-color: transparent; } footer { background-color: #262626; color: #fff; font-size: 0.8rem; position: absolute; bottom: 0; width: 100%; padding-top: 10px; padding-bottom: 10px; } footer a, footer a:visited, footer a:hover { color: #fecd1b; } footer a:hover { text-decoration: underline; } .link-color { color: #fecd1b; } pre { background-color: #f5f5f5; border: 1px solid #ccc; border-radius: 4px; padding: 9.5px; font-size: 0.8rem; } .btn.active { background-color: #e7e7e7; } .card { margin-bottom: 5px !important; overflow-x: auto; } .navbar-brand { padding: 5px; margin-right: 0; } .table { margin-bottom: 0; } .swh-table thead { background-color: #f2f4f5; border-top: 1px solid rgba(0, 0, 0, 0.2); font-weight: normal; } .swh-table-striped th { border-top: none; } .swh-table-striped tbody tr:nth-child(even) { background-color: #f2f4f5; } .swh-table-striped tbody tr:nth-child(odd) { background-color: #fff; } .swh-web-app-link a { text-decoration: none; border: none; } .swh-web-app-link:hover { background-color: #efeff2; } .table > thead > tr > th { border-top: none; border-bottom: 1px solid #e20026; } .table > tbody > tr > td { border-style: none; } .sitename .first-word, .sitename .second-word { color: rgba(0, 0, 0, 0.75); font-weight: normal; font-size: 1.2rem; } .sitename .first-word { - font-family: 'Alegreya Sans', sans-serif; + font-family: "Alegreya Sans", sans-serif; } .sitename .second-word { - font-family: 'Alegreya', serif; + font-family: "Alegreya", serif; } .swh-counter { font-size: 150%; } @media (max-width: 600px) { .swh-counter-container { margin-top: 1rem; } } .swh-http-error { margin: 0 auto; text-align: center; } .swh-http-error-head { color: #2d353c; font-size: 30px; } .swh-http-error-code { bottom: 60%; color: #2d353c; font-size: 96px; line-height: 80px; margin-bottom: 10px !important; } .swh-http-error-desc { font-size: 12px; color: #647788; text-align: center; } .swh-http-error-desc pre { display: inline-block; text-align: left; max-width: 800px; white-space: pre-wrap; } .swh-list-unstyled { list-style: none; } .popover { max-width: 97%; z-index: 40000; } .modal { text-align: center; padding: 0 !important; z-index: 50000; } .modal::before { - content: ''; + content: ""; display: inline-block; height: 100%; vertical-align: middle; margin-right: -4px; } .modal-dialog { display: inline-block; text-align: left; vertical-align: middle; } .dropdown-submenu { position: relative; } .dropdown-submenu .dropdown-menu { top: 0; left: -100%; margin-top: -5px; margin-left: -2px; } .dropdown-item:hover, .dropdown-item:focus { background-color: rgba(0, 0, 0, 0.1); } a.dropdown-left::before { content: "\f035e"; - font-family: 'Material Design Icons'; + font-family: "Material Design Icons"; display: block; width: 20px; height: 20px; float: left; margin-left: 0; } #swh-navbar { border-top-style: none; border-left-style: none; border-right-style: none; border-bottom-style: solid; border-bottom-width: 5px; - border-image: linear-gradient(to right, rgb(226, 0, 38) 0%, rgb(254, 205, 27) 100%) 1 1 1 1; + border-image: + linear-gradient( + to right, + rgb(226, 0, 38) 0%, + rgb(254, 205, 27) 100% + ) + 1 1 1 1; width: 100%; padding: 5px; margin-bottom: 10px; margin-top: 30px; justify-content: normal; flex-wrap: nowrap; height: 72px; overflow: hidden; } #back-to-top { display: none; position: fixed; bottom: 30px; right: 30px; z-index: 10; } #back-to-top a img { display: block; width: 32px; height: 32px; background-size: 32px 32px; text-indent: -999px; overflow: hidden; } .swh-top-bar { direction: ltr; height: 30px; position: fixed; top: 0; left: 0; width: 100%; z-index: 99999; background-color: #262626; color: #fff; text-align: center; font-size: 14px; } .swh-top-bar ul { margin-top: 4px; padding-left: 0; white-space: nowrap; } .swh-top-bar li { display: inline-block; margin-left: 10px; margin-right: 10px; } .swh-top-bar a, .swh-top-bar a:visited { color: white; } .swh-top-bar a.swh-current-site, .swh-top-bar a.swh-current-site:visited { color: #fecd1b; } .swh-position-left { position: absolute; left: 0; } .swh-position-right { position: absolute; right: 0; } .swh-background-gray { background: #efeff2; } .swh-donate-link { border: 1px solid #fecd1b; background-color: #e20026; color: white !important; padding: 3px; border-radius: 3px; } .swh-navbar-content h4 { padding-top: 7px; } .swh-navbar-content .bread-crumbs { display: block; margin-left: -40px; } .swh-navbar-content .bread-crumbs li.bc-no-root { padding-top: 7px; } .main-sidebar { margin-top: 30px; } .content-wrapper { background: none; } .brand-image { max-height: 40px; } .brand-link { padding-top: 18.5px; padding-bottom: 18px; padding-left: 4px; border-bottom: 5px solid #e20026 !important; } .navbar-header a, ul.dropdown-menu a, ul.navbar-nav a, ul.nav-sidebar a { border-bottom-style: none; color: #323232; } .swh-sidebar .nav-link.active { color: #323232 !important; background-color: #e7e7e7 !important; } .nav-tabs .nav-link.active { border-top: 3px solid #e20026; } .swh-image-error { width: 80px; height: auto; } @media (max-width: 600px) { .card { min-width: 80%; } .swh-image-error { width: 40px; height: auto; } .swh-donate-link { display: none; } } .form-check-label { padding-top: 4px; } .swhid { white-space: pre-wrap; } .swhid .swhid-option { display: inline-block; margin-right: 5px; line-height: 1rem; } .nav-pills .nav-link:not(.active):hover { color: rgba(0, 0, 0, 0.55); } .swh-heading-color { color: #e20026 !important; } .sidebar-mini.sidebar-collapse .main-sidebar:hover { width: 4.6rem; } .sidebar-mini.sidebar-collapse .main-sidebar:hover .user-panel > .info, .sidebar-mini.sidebar-collapse .main-sidebar:hover .nav-sidebar .nav-link p, .sidebar-mini.sidebar-collapse .main-sidebar:hover .brand-text { visibility: hidden !important; } .sidebar .nav-link p, .main-sidebar .brand-text, .sidebar .user-panel .info { transition: none; } .sidebar-mini.sidebar-mini.sidebar-collapse .sidebar { padding-right: 0; } .swh-words-logo { position: absolute; top: 0; left: 0; width: 73px; height: 73px; text-align: center; font-size: 10pt; color: rgba(0, 0, 0, 0.75); } .swh-words-logo:hover { text-decoration: none; } .swh-words-logo-swh { line-height: 1; padding-top: 13px; visibility: hidden; } hr.swh-faded-line { border: 0; height: 1px; background-image: linear-gradient(to left, #f0f0f0, #8c8b8b, #f0f0f0); } /* Ensure that section title with link is colored like standard section title */ .swh-readme h1 a, .swh-readme h2 a, .swh-readme h3 a, .swh-readme h4 a, .swh-readme h5 a, .swh-readme h6 a { color: #e20026; } /* Make list compact in reStructuredText rendering */ .swh-rst li p { margin-bottom: 0; } .swh-readme-txt pre { background: none; border: none; } -.swh-coverage-col { - padding-left: 10px; - padding-right: 10px; -} - .swh-coverage { - height: calc(65px + 1em); padding-top: 0.3rem; border: none; + overflow: visible; } .swh-coverage a { text-decoration: none; } +.swh-coverage-col { + padding-left: 10px; + padding-right: 10px; +} + +.swh-coverage-header { + padding-top: 0; + padding-bottom: 0; +} + .swh-coverage-logo { display: block; width: 100%; height: 50px; margin-left: auto; margin-right: auto; object-fit: contain; /* polyfill for old browsers, see https://github.com/bfred-it/object-fit-images */ - font-family: 'object-fit: contain;'; + font-family: "object-fit: contain;"; } .swh-coverage-list { width: 100%; height: 320px; border: none; } +.swh-coverage-chevron { + position: absolute; + right: 0; +} + +.swh-coverage .card-header .mdi { + transition: 0.3s transform ease-in-out; +} + +.swh-coverage .card-header .collapsed .mdi { + transform: rotate(90deg); +} + +.swh-coverage-info-body { + max-height: 150px; + overflow-y: auto; + overflow-x: hidden; + scrollbar-width: thin; /* Firefox only */ + padding: 0; +} + +/* Thin scrollbar for chromium based browsers */ + +.swh-coverage-info-body::-webkit-scrollbar { + width: 4px; +} + +.swh-coverage-info-body::-webkit-scrollbar-track { + background: #eff0f1; +} + +.swh-coverage-info-body::-webkit-scrollbar-thumb { + background: #909396; +} + tr.swh-tr-hover-highlight:hover td { background: #ededed; } tr.swh-api-doc-route a { text-decoration: none; } .swh-apidoc .col { margin: 10px; } .swh-apidoc .swh-rst blockquote { border: 0; margin: 0; padding: 0; } a.toggle-col { text-decoration: none; } a.toggle-col.col-hidden { text-decoration: line-through; } .admonition.warning { background: #fcf8e3; border: 1px solid #faebcc; padding: 15px; border-radius: 4px; } .admonition.warning p { margin-bottom: 0; } .admonition.warning .first { font-size: 1.5rem; } .swh-popover { max-height: 50vh; overflow-y: auto; overflow-x: auto; padding: 0; } @media screen and (min-width: 768px) { .swh-popover { max-width: 50vw; } } .swh-popover pre { white-space: pre-wrap; margin-bottom: 0; } .d3-wrapper { position: relative; height: 0; width: 100%; padding: 0; /* padding-bottom will be overwritten by JavaScript later */ padding-bottom: 100%; } .d3-wrapper > svg { position: absolute; height: 100%; width: 100%; left: 0; top: 0; } div.d3-tooltip { position: absolute; text-align: center; width: auto; height: auto; padding: 2px; font: 12px sans-serif; background: white; border: 1px solid black; border-radius: 4px; pointer-events: none; } .page-link { cursor: pointer; } .wrapper { overflow: hidden; } .swh-badge { padding-bottom: 1rem; cursor: pointer; } .swh-badge-html, .swh-badge-md, .swh-badge-rst { white-space: pre-wrap; } /* Material Design icons alignment tweaks */ .mdi { display: inline-block; } .mdi-camera { transform: translateY(1px); } .mdi-source-commit { transform: translateY(2px); } /* To set icons at a fixed width. Great to use when different icon widths throw off alignment. Courtesy of Font Awesome. */ .mdi-fw { text-align: center; width: 1.25em; } .main-header .nav-link { height: inherit; } .nav-sidebar .nav-header:not(:first-of-type) { padding-top: 1rem; } .nav-sidebar .nav-link { padding-top: 0; padding-bottom: 0; } .nav-sidebar > .nav-item .nav-icon { vertical-align: sub; } .swh-search-icon { line-height: 1rem; vertical-align: middle; } .swh-search-navbar { position: absolute; top: 0.7rem; right: 15rem; z-index: 50000; width: 500px; } .sidebar-collapse .swh-search-navbar { right: 4rem; } .swh-corner-ribbon { width: 200px; background: #fecd1b; color: #e20026; position: absolute; text-align: center; letter-spacing: 1px; box-shadow: 0 0 3px rgba(0, 0, 0, 0.3); top: 55px; right: -50px; left: auto; transform: rotate(45deg); z-index: 2000; } @media screen and (max-width: 600px) { .swh-corner-ribbon { top: 53px; right: -65px; } } .invalid-feedback { font-size: 100%; } diff --git a/static/img/logos/cgit.png b/static/img/logos/cgit.png new file mode 100644 index 00000000..425528ee Binary files /dev/null and b/static/img/logos/cgit.png differ diff --git a/static/img/logos/cran.png b/static/img/logos/cran.png new file mode 100644 index 00000000..16f1734a Binary files /dev/null and b/static/img/logos/cran.png differ diff --git a/static/img/logos/cran.svg b/static/img/logos/cran.svg deleted file mode 100644 index 7b162d43..00000000 --- a/static/img/logos/cran.svg +++ /dev/null @@ -1,33 +0,0 @@ -<!-- -Copyright (C) 2015-2016 The R Foundation - -You can distribute this logo under the terms of the Creative -Commons Attribution-ShareAlike 4.0 International license (CC-BY-SA -4.0) or (at your option) the GNU General Public License version 2 -(GPL-2). - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -You should have received a copy of the GNU General Public License -along with this program; if not, a copy is available at -https://www.R-project.org/Licenses/ - -The text of the CC BY-SA 4.0 license is available at -https://creativecommons.org/licenses/by-sa/4.0/ ---> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid" width="724" height="561" viewBox="0 0 724 561"> - <defs> - <linearGradient id="gradientFill-1" x1="0" x2="1" y1="0" y2="1" gradientUnits="objectBoundingBox" spreadMethod="pad"> - <stop offset="0" stop-color="rgb(203,206,208)" stop-opacity="1"/> - <stop offset="1" stop-color="rgb(132,131,139)" stop-opacity="1"/> - </linearGradient> - <linearGradient id="gradientFill-2" x1="0" x2="1" y1="0" y2="1" gradientUnits="objectBoundingBox" spreadMethod="pad"> - <stop offset="0" stop-color="rgb(39,109,195)" stop-opacity="1"/> - <stop offset="1" stop-color="rgb(22,92,170)" stop-opacity="1"/> - </linearGradient> - </defs> - <path d="M361.453,485.937 C162.329,485.937 0.906,377.828 0.906,244.469 C0.906,111.109 162.329,3.000 361.453,3.000 C560.578,3.000 722.000,111.109 722.000,244.469 C722.000,377.828 560.578,485.937 361.453,485.937 ZM416.641,97.406 C265.289,97.406 142.594,171.314 142.594,262.484 C142.594,353.654 265.289,427.562 416.641,427.562 C567.992,427.562 679.687,377.033 679.687,262.484 C679.687,147.971 567.992,97.406 416.641,97.406 Z" fill="url(#gradientFill-1)" fill-rule="evenodd"/> - <path d="M550.000,377.000 C550.000,377.000 571.822,383.585 584.500,390.000 C588.899,392.226 596.510,396.668 602.000,402.500 C607.378,408.212 610.000,414.000 610.000,414.000 L696.000,559.000 L557.000,559.062 L492.000,437.000 C492.000,437.000 478.690,414.131 470.500,407.500 C463.668,401.969 460.755,400.000 454.000,400.000 C449.298,400.000 420.974,400.000 420.974,400.000 L421.000,558.974 L298.000,559.026 L298.000,152.938 L545.000,152.938 C545.000,152.938 657.500,154.967 657.500,262.000 C657.500,369.033 550.000,377.000 550.000,377.000 ZM496.500,241.024 L422.037,240.976 L422.000,310.026 L496.500,310.002 C496.500,310.002 531.000,309.895 531.000,274.877 C531.000,239.155 496.500,241.024 496.500,241.024 Z" fill="url(#gradientFill-2)" fill-rule="evenodd"/> -</svg> diff --git a/static/img/logos/elife.png b/static/img/logos/elife.png new file mode 100644 index 00000000..9a5cb7cb Binary files /dev/null and b/static/img/logos/elife.png differ diff --git a/static/img/logos/framagit.png b/static/img/logos/framagit.png deleted file mode 100644 index 0b78ed4f..00000000 Binary files a/static/img/logos/framagit.png and /dev/null differ diff --git a/static/img/logos/gitea.png b/static/img/logos/gitea.png new file mode 100644 index 00000000..b624d2d5 Binary files /dev/null and b/static/img/logos/gitea.png differ diff --git a/static/img/logos/gitlab.png b/static/img/logos/gitlab.png new file mode 100644 index 00000000..1eb3c77d Binary files /dev/null and b/static/img/logos/gitlab.png differ diff --git a/static/img/logos/gitlab.svg b/static/img/logos/gitlab.svg deleted file mode 100644 index 74505975..00000000 --- a/static/img/logos/gitlab.svg +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<svg width="962px" height="342px" viewBox="0 0 962 342" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"> - <!-- Generator: Sketch 3.3.2 (12043) - http://www.bohemiancoding.com/sketch --> - <title>wm_no_bg</title> - <desc>Created with Sketch.</desc> - <defs></defs> - <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"> - <g id="wm_no_bg" sketch:type="MSLayerGroup"> - <g id="word" transform="translate(498.000000, 107.000000)" fill="#8C929D" sketch:type="MSShapeGroup"> - <path d="M237.0109,3.0669 L220.6379,3.0669 L220.6899,124.9329 L286.9259,124.9329 L286.9259,109.8629 L237.0629,109.8629 L237.0109,3.0669 Z" id="Fill-2"></path> - <path d="M349.9956,103.5367 C345.9026,107.8157 339.0186,112.0957 329.7156,112.0957 C317.2496,112.0957 312.2266,105.9557 312.2266,97.9547 C312.2266,85.8617 320.5986,80.0937 338.4606,80.0937 C341.8096,80.0937 347.2046,80.4657 349.9956,81.0237 L349.9956,103.5367 Z M333.0646,29.6727 C319.8426,29.6727 307.7156,34.3597 298.2526,42.1617 L304.0396,52.1857 C310.7376,48.2787 318.9246,44.3707 330.6456,44.3707 C344.0416,44.3707 349.9956,51.2557 349.9956,62.7907 L349.9956,68.7447 C347.3906,68.1867 341.9956,67.8137 338.6466,67.8137 C309.9936,67.8137 295.4816,77.8607 295.4816,98.8857 C295.4816,117.6767 307.0166,127.1657 324.5056,127.1657 C336.2866,127.1657 347.5766,121.7697 351.4836,113.0257 L354.4606,124.9327 L365.9966,124.9327 L365.9966,62.6047 C365.9966,42.8827 357.4376,29.6727 333.0646,29.6727 L333.0646,29.6727 Z" id="Fill-3"></path> - <path d="M418.8252,112.6533 C412.6852,112.6533 407.2892,111.9093 403.1962,110.0483 L403.1962,59.5343 L403.1962,53.6743 C408.7782,49.0223 415.6622,45.6733 424.4072,45.6733 C440.2212,45.6733 446.3612,56.8363 446.3612,74.8843 C446.3612,100.5593 436.5002,112.6533 418.8252,112.6533 M425.7062,29.6723 C411.0732,29.6723 403.1962,39.6273 403.1962,39.6273 L403.1962,23.9053 L403.1442,3.0673 L395.7622,3.0673 L387.1442,3.0673 L387.1962,121.9563 C395.1962,125.3053 406.1732,127.1653 418.0812,127.1653 C448.5942,127.1653 463.2922,107.6303 463.2922,73.9543 C463.2922,47.3483 449.7072,29.6723 425.7062,29.6723" id="Fill-5"></path> - <path d="M59.0316,16.2769 C73.5436,16.2769 82.8466,21.1139 88.9866,25.9519 L96.0226,13.7639 C86.4326,5.3539 73.5336,0.8339 59.7756,0.8339 C24.9836,0.8339 0.6106,22.0449 0.6106,64.8369 C0.6106,109.6769 26.9046,127.1659 56.9846,127.1659 C72.0556,127.1659 84.8936,123.6309 93.2656,120.0959 L92.9226,72.1869 L92.9226,66.5349 L92.9226,57.1159 L48.2696,57.1159 L48.2696,72.1869 L76.7356,72.1869 L77.0786,108.5599 C73.3576,110.4209 66.8456,111.9089 58.1016,111.9089 C33.9146,111.9089 17.7276,96.6939 17.7276,64.6509 C17.7276,32.0919 34.4726,16.2769 59.0316,16.2769" id="Fill-7"></path> - <path d="M174.1768,3.0669 L158.1758,3.0669 L158.2278,23.5329 L158.2278,31.9059 L158.2278,36.7859 L158.2278,45.3019 L158.2278,94.0479 L158.2278,94.2339 C158.2278,113.9559 166.7868,127.1659 191.1598,127.1659 C194.5268,127.1659 197.8218,126.8599 201.0208,126.2789 L201.0208,111.9099 C198.7048,112.2649 196.2328,112.4669 193.5788,112.4669 C180.1828,112.4669 174.2288,105.5829 174.2288,94.0479 L174.2288,45.3019 L201.0208,45.3019 L201.0208,31.9059 L174.2288,31.9059 L174.1768,3.0669 Z" id="Fill-9"></path> - <path d="M117.575,124.933 L133.576,124.933 L133.576,31.905 L117.575,31.905 L117.575,124.933 Z" id="Fill-11"></path> - <path d="M117.575,19.068 L133.576,19.068 L133.576,3.067 L117.575,3.067 L117.575,19.068 Z" id="Fill-13"></path> - </g> - <g id="logo" sketch:type="MSShapeGroup"> - <path d="M185.3984,341.1298 L185.3984,341.1298 L253.4114,131.8078 L117.3854,131.8078 L185.3984,341.1298 L185.3984,341.1298 Z" id="Fill-14" fill="#E24329"></path> - <path id="Fill-15" fill="#E24329"></path> - <path d="M185.3984,341.1294 L117.3854,131.8084 L22.0664,131.8084 L185.3984,341.1294 Z" id="Fill-16" fill="#FC6D26"></path> - <path id="Fill-17" fill="#E24329"></path> - <path d="M22.0664,131.8081 L22.0664,131.8081 L1.3974,195.4191 C-0.4876,201.2211 1.5774,207.5771 6.5134,211.1621 L185.3984,341.1291 L22.0664,131.8081 Z" id="Fill-18" fill="#FCA326"></path> - <path id="Fill-19" fill="#E24329"></path> - <path d="M22.0664,131.8083 L117.3854,131.8083 L76.4214,5.7353 C74.3134,-0.7517 65.1364,-0.7517 63.0294,5.7353 L22.0664,131.8083 Z" id="Fill-20" fill="#E24329"></path> - <path d="M185.3984,341.1294 L253.4114,131.8084 L348.7304,131.8084 L185.3984,341.1294 Z" id="Fill-21" fill="#FC6D26"></path> - <path d="M348.7303,131.8081 L348.7303,131.8081 L369.3993,195.4191 C371.2843,201.2211 369.2193,207.5771 364.2833,211.1621 L185.3983,341.1291 L348.7303,131.8081 Z" id="Fill-22" fill="#FCA326"></path> - <path d="M348.7303,131.8083 L253.4113,131.8083 L294.3753,5.7353 C296.4833,-0.7517 305.6603,-0.7517 307.7673,5.7353 L348.7303,131.8083 Z" id="Fill-23" fill="#E24329"></path> - </g> - </g> - </g> -</svg> \ No newline at end of file diff --git a/static/img/logos/guix.png b/static/img/logos/guix.png new file mode 100644 index 00000000..7693a131 Binary files /dev/null and b/static/img/logos/guix.png differ diff --git a/static/img/logos/guix.svg b/static/img/logos/guix.svg deleted file mode 100644 index ecd4bc42..00000000 --- a/static/img/logos/guix.svg +++ /dev/null @@ -1,177 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - height="45.227978mm" - width="124.8896mm" - viewBox="0 0 442.52218 160.25662" - id="svg3338" - version="1.1" - inkscape:version="0.92.4 (5da689c313, 2019-01-14)" - sodipodi:docname="guix.svg"> - <defs - id="defs3344"> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4702-3" - id="linearGradient3936" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.4874381,0,0,1.4874381,1284.8057,-24.050665)" - x1="142.96875" - y1="63.65625" - x2="176.60477" - y2="70.667412" /> - <linearGradient - id="linearGradient4702-3"> - <stop - style="stop-color:#ff0000;stop-opacity:0.58431375;" - offset="0" - id="stop4704-1" /> - <stop - style="stop-color:#ffcc00;stop-opacity:1;" - offset="1" - id="stop4706-8" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4702-3" - id="linearGradient3932" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.4874381,0,0,1.4874381,1284.7576,-1291.8882)" - x1="113.5146" - y1="1004.8033" - x2="78.000107" - y2="922.07178" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4696-5" - id="linearGradient3929" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-0.83291399,0,0,0.83291399,1519.4606,-667.62588)" - x1="108.08774" - y1="1025.709" - x2="80.655251" - y2="1043.709" /> - <linearGradient - id="linearGradient4696-5"> - <stop - style="stop-color:#ffb638;stop-opacity:1;" - offset="0" - id="stop4698-6" /> - <stop - style="stop-color:#f0ae26;stop-opacity:1;" - offset="1" - id="stop4700-2" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4702-3" - id="linearGradient3926" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-1.4874381,0,0,1.4874381,1586.895,-24.051145)" - x1="142.96875" - y1="63.65625" - x2="177.04297" - y2="69.791016" /> - </defs> - <sodipodi:namedview - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1" - objecttolerance="10" - gridtolerance="10" - guidetolerance="10" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="988" - id="namedview3342" - showgrid="false" - inkscape:zoom="1.8132778" - inkscape:cx="358.5004" - inkscape:cy="54.025567" - inkscape:window-x="0" - inkscape:window-y="38" - inkscape:window-maximized="1" - inkscape:current-layer="svg3338" /> - <metadata - id="metadata3340"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - id="g3398" - transform="translate(-1305.3034,-46.601235)"> - <g - id="g3122" - transform="translate(1285.8501,-737.48576)"> - <path - inkscape:connector-curvature="0" - id="path3240" - style="font-style:normal;font-weight:bold;font-size:67.20256042px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1.46569705" - d="m 288.64105,937.61034 c -4.6172,2.24443 -9.41066,3.92778 -14.38041,5.04992 -4.96987,1.12228 -10.1,1.68335 -15.39041,1.68335 -11.95965,0 -21.43436,-3.33461 -28.42416,-10.00382 -6.98981,-6.70117 -10.48471,-15.77515 -10.48471,-27.22175 0,-11.57481 3.55902,-20.68079 10.6771,-27.31797 7.11804,-6.63704 16.86528,-9.95558 29.24177,-9.95566 4.77738,8e-5 9.34642,0.44896 13.70708,1.34666 4.39261,0.89785 8.52878,2.22847 12.40852,3.99188 v 14.86137 c -4.00799,-2.27644 -7.99988,-3.9758 -11.97566,-5.09807 -3.94385,-1.12216 -7.90368,-1.68326 -11.87948,-1.68334 -7.37461,8e-5 -13.06584,2.06816 -17.07373,6.20427 -3.97588,4.10416 -5.9638,9.98777 -5.96377,17.65086 -3e-5,7.59899 1.92377,13.46663 5.7714,17.60282 3.84755,4.1362 9.31435,6.20429 16.40039,6.20429 1.92375,0 3.70327,-0.11285 5.33855,-0.33667 1.66725,-0.2565 3.15819,-0.64139 4.47284,-1.15438 v -13.94757 h -11.30233 v -12.40846 h 28.85701 v 34.53227" /> - <path - inkscape:connector-curvature="0" - id="path3242" - style="font-style:normal;font-weight:bold;font-size:67.20256042px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1.46569705" - d="m 303.55051,921.97942 v -32.897 h 17.31421 v 5.38664 c -3e-5,2.91781 -0.0161,6.58906 -0.0481,11.01376 -0.0321,4.39271 -0.0481,7.32651 -0.0481,8.8014 -3e-5,4.32849 0.11212,7.45468 0.33665,9.37855 0.22442,1.89178 0.60919,3.27041 1.15428,4.1362 0.70537,1.12213 1.61918,1.98793 2.74143,2.59707 1.15425,0.60914 2.46883,0.91386 3.94378,0.91386 3.59106,0 6.41263,-1.37878 8.46472,-4.1362 2.05202,-2.75742 3.07804,-6.58903 3.07809,-11.49473 v -26.59655 h 17.21801 v 53.86644 h -17.21801 v -7.79136 c -2.59718,3.14216 -5.35463,5.46676 -8.27234,6.97379 -2.88574,1.47478 -6.07604,2.21232 -9.57091,2.21232 -6.22031,0 -10.96568,-1.90775 -14.23613,-5.72325 -3.2384,-3.81566 -4.8576,-9.36258 -4.8576,-16.64094" /> - <path - inkscape:connector-curvature="0" - id="path3244" - style="font-style:normal;font-weight:bold;font-size:67.20256042px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1.46569705" - d="m 374.34637,889.08242 h 17.218 v 53.86644 h -17.218 v -53.86644 m 0,-20.96944 h 17.218 v 14.04376 h -17.218 v -14.04376" /> - <path - inkscape:connector-curvature="0" - id="path3246" - style="font-style:normal;font-weight:bold;font-size:67.20256042px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;stroke-width:1.46569705" - d="m 421.81614,915.39038 -19.43038,-26.30796 h 18.22801 l 11.01376,15.96754 11.15804,-15.96754 h 18.22801 l -19.43039,26.2118 20.39229,27.65464 h -18.22801 l -12.11994,-17.02569 -11.97567,17.02569 h -18.22801 l 20.39229,-27.55848" /> - </g> - <path - inkscape:connector-curvature="0" - style="font-style:normal;font-weight:bold;font-size:144px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none" - d="m 1557.9367,46.602435 c -2.6825,4.90263 -5.4059,8.89401 -8.1809,12.03897 -2.6825,3.05258 -5.6406,5.49427 -8.8781,7.34422 -3.1451,1.75757 -6.7135,3.02514 -10.691,3.76506 -3.885,0.64751 -8.3459,0.97629 -13.4334,0.9761 -3.7529,0 -7.1256,-0.1922 -10.0867,-0.55773 -0.012,0 -0.034,0 -0.047,0 -0.3754,-0.0273 -1.1508,-0.15334 -1.9523,-0.27891 -0.8442,-0.13218 -1.7071,-0.25955 -3.0678,-0.5113 -24.9421,-4.61489 -33.2141,12.7003 -35.0013,17.47744 -0.2797,0.74767 -0.4183,1.20845 -0.4183,1.20845 l -30.3066,84.505085 -18.593,31.60821 h 37.1395 c 15.2535,-33.96261 29.9183,-104.875515 45.5993,-111.139545 3.3988,0.47537 7.6118,0.69713 12.6897,0.69713 6.6601,0 12.6232,-0.79843 17.8957,-2.46349 5.2726,-1.66502 10.0151,-4.24757 14.2702,-7.76263 4.255,-3.60748 8.1051,-8.20868 11.5276,-13.75881 3.515,-5.54998 6.8486,-12.21732 9.9937,-19.98743 l -8.4597,-3.16082 z" - id="path3143" /> - <path - style="font-style:normal;font-weight:bold;font-size:144px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3936);fill-opacity:1;stroke:none" - d="m 1557.9358,46.605905 c -2.6826,4.90263 -5.4057,8.8885 -8.1808,12.03346 -2.6824,3.05259 -5.6417,5.49543 -8.8792,7.34538 -0.7789,0.43527 -1.5819,0.83524 -2.4125,1.20983 -0.01,0.003 -0.014,0.0109 -0.022,0.0144 -1.0455,0.73525 -2.3902,1.36643 -4.2128,1.80033 -21.0208,5.00504 -35.3388,23.73821 -36.6837,25.5504 0.6098,-0.50134 1.2236,-0.91065 1.8364,-1.22422 0.092,-0.0488 0.1814,-0.093 0.2736,-0.13683 0.015,-0.007 0.029,-0.0148 0.043,-0.0216 0.1068,-0.0498 0.2172,-0.0941 0.3241,-0.13682 3.3988,0.47537 7.6109,0.69853 12.6888,0.69853 6.6601,0 12.6228,-0.805 17.8954,-2.47007 5.2725,-1.66501 10.0108,-4.2408 14.2658,-7.75586 4.2551,-3.60747 8.1069,-8.21164 11.5294,-13.76177 3.515,-5.55 6.8504,-12.22084 9.9955,-19.99096 l -8.4616,-3.1542 z" - id="path3145" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - style="font-style:normal;font-weight:bold;font-size:144px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:#ffcc00;fill-opacity:1;stroke:none" - d="m 1313.7642,46.602455 c 2.6826,4.90263 5.4059,8.89399 8.1809,12.03895 2.6825,3.05258 5.6407,5.49427 8.8782,7.34422 3.145,1.75757 6.7134,3.02514 10.6909,3.76506 3.8851,0.6477 8.3459,0.97629 13.4334,0.9761 3.7529,0 7.1256,-0.1922 10.0867,-0.55773 0.012,0 0.035,0 0.047,0 0.3754,-0.0269 1.1508,-0.15333 1.9523,-0.27891 0.8442,-0.13218 1.7071,-0.25955 3.0678,-0.5113 24.9421,-4.61489 33.2141,12.7003 35.0013,17.47744 0.2797,0.74767 0.4183,1.20845 0.4183,1.20845 l 30.3066,84.505085 18.593,31.60821 h -37.1395 c -15.2535,-33.96261 -29.9183,-104.875515 -45.5993,-111.139545 -3.3988,0.47537 -7.6118,0.69713 -12.6897,0.69713 -6.6601,0 -12.6232,-0.79843 -17.8957,-2.46349 -5.2726,-1.66502 -10.0151,-4.24757 -14.2702,-7.76263 -4.255,-3.60748 -8.105,-8.20867 -11.5276,-13.75881 -3.515,-5.54993 -6.8486,-12.21728 -9.9937,-19.98743 l 8.4598,-3.1608 z" - id="path3147" /> - <path - sodipodi:nodetypes="ccccccccsscccccccccccc" - id="path3149" - d="m 1313.7627,46.601235 c 2.6826,4.90262 5.4059,8.89399 8.1809,12.03894 2.6825,3.05259 5.6407,5.49427 8.8781,7.34422 3.1451,1.75757 6.7135,3.02514 10.691,3.76507 3.8851,0.64768 8.3459,0.97628 13.4334,0.97609 3.7529,0 7.1256,-0.19221 10.0867,-0.55772 0.012,0 0.035,0 0.047,0 0.3754,-0.027 1.1508,-0.15335 1.9523,-0.27892 0.8442,-0.13218 1.7071,-0.25955 3.0678,-0.5113 24.9421,-4.61489 33.2141,12.70029 35.0013,17.47744 0.2797,0.74767 0.4183,1.20845 0.4183,1.20845 l 30.3066,84.505095 15.6181,31.60819 h -34.1646 c -15.2535,-33.9626 -29.9183,-104.875505 -45.5993,-111.139535 -3.3988,0.47537 -7.6118,0.69713 -12.6897,0.69713 -6.6601,0 -12.6232,-0.79843 -17.8957,-2.46349 -5.2726,-1.66502 -10.0151,-4.24758 -14.2701,-7.76263 -4.2551,-3.60748 -8.1051,-8.20867 -11.5277,-13.7588 -3.515,-5.54995 -6.8486,-12.21728 -9.9937,-19.98743 l 8.4598,-3.1608 z" - style="font-style:normal;font-weight:bold;font-size:144px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3932);fill-opacity:1;stroke:none" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path3151" - style="font-style:normal;font-weight:bold;font-size:144px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3929);fill-opacity:1;stroke:none" - d="m 1435.8193,172.5566 -18.52,31.62143 h 37.1209" - sodipodi:nodetypes="ccc" /> - <path - style="font-style:normal;font-weight:bold;font-size:144px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans Bold';letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient3926);fill-opacity:1;stroke:none" - d="m 1313.7667,46.605905 -8.4616,3.1542 c 0.9829,2.42817 1.9835,4.75137 3.003,6.96371 0.2039,0.44246 0.4068,0.87683 0.6121,1.31064 8e-4,0.002 -8e-4,0.006 0,0.007 0.2044,0.4318 0.4135,0.85862 0.6193,1.28184 0.069,0.14106 0.1401,0.27758 0.2089,0.41768 0.3452,0.70349 0.6877,1.40177 1.037,2.08119 0,0.003 0.01,0.004 0.01,0.007 0.2082,0.40484 0.4169,0.80634 0.6265,1.20263 0.8454,1.59852 1.7025,3.12828 2.5709,4.58726 0.2168,0.36432 0.4298,0.7174 0.6481,1.073 0.085,0.13784 0.1672,0.27395 0.252,0.41048 0.1351,0.21746 0.2749,0.43399 0.4105,0.64812 0.2139,0.34687 0.4237,0.69034 0.6409,1.0298 0.3462,0.54084 0.7041,1.06956 1.0586,1.59149 0.09,0.13178 0.1764,0.26551 0.2665,0.39607 0.225,0.32622 0.4486,0.64634 0.6769,0.96499 0.4544,0.6341 0.9152,1.25393 1.3827,1.85795 0.2337,0.302 0.4687,0.59851 0.7057,0.89296 0.474,0.58892 0.9532,1.16257 1.4403,1.72113 0.3692,0.42348 0.7467,0.83988 1.1234,1.24584 0.119,0.12822 0.2403,0.2552 0.36,0.38166 0.5012,0.52939 1.0055,1.04257 1.5195,1.54109 0.2564,0.24866 0.511,0.49359 0.7706,0.73454 0.2608,0.24217 0.5209,0.47857 0.7849,0.71294 0.2628,0.23322 0.5262,0.45866 0.7922,0.68413 0.7978,0.65907 1.6161,1.28595 2.4484,1.87955 2.2197,1.58292 4.563,2.93443 7.0357,4.05436 0.3091,0.14 0.6159,0.27768 0.929,0.41048 0.6283,0.26652 1.2637,0.51855 1.9084,0.75614 0.3213,0.11842 0.6396,0.22723 0.965,0.33846 0.3254,0.11123 0.657,0.22 0.9866,0.32406 0.3295,0.10407 0.6588,0.20515 0.9937,0.30246 0.6699,0.19463 1.3538,0.37949 2.0452,0.5473 0.3458,0.0839 0.6931,0.16039 1.0442,0.23765 0.3512,0.0773 0.7021,0.15261 1.0586,0.22324 0.3588,0.0711 0.7159,0.13718 1.0802,0.20164 0.7239,0.12808 1.458,0.24373 2.2036,0.34566 1.1184,0.15292 2.2607,0.27964 3.4279,0.37447 0.7781,0.0633 1.5694,0.1135 2.3692,0.15123 0.7999,0.0377 1.6125,0.0595 2.4341,0.072 0.4108,0.006 0.8224,0.007 1.2386,0.007 0.6348,0 1.2574,-2.1e-4 1.8652,-0.007 1.2156,-0.014 2.3763,-0.0437 3.4854,-0.0864 0.5521,-0.0213 1.0943,-0.0435 1.6203,-0.072 0.5282,-0.0287 1.0462,-0.0646 1.5483,-0.10083 1.5062,-0.10864 2.895,-0.24661 4.1696,-0.42487 0.1069,0.0427 0.2173,0.087 0.3241,0.13682 0.015,0.006 0.028,0.0148 0.043,0.0216 0.092,0.0439 0.1815,0.088 0.2736,0.13682 0.6131,0.31376 1.2262,0.72249 1.8364,1.22423 -1.3421,-1.80851 -15.6604,-20.54497 -36.6837,-25.5504 -1.8226,-0.43396 -3.1673,-1.06505 -4.2128,-1.80034 -0.01,-0.003 -0.014,-0.0108 -0.022,-0.0144 -0.8287,-0.37374 -1.6352,-0.77569 -2.4125,-1.20983 0,-8e-4 -0.01,7.9e-4 -0.01,0 -0.2005,-0.11459 -0.3993,-0.23372 -0.5977,-0.35287 0,-8e-4 -0.01,8e-4 -0.01,0 -0.2001,-0.12025 -0.3925,-0.24238 -0.5905,-0.36726 -0.3976,-0.25081 -0.7922,-0.50819 -1.181,-0.77775 -0.1936,-0.13419 -0.3847,-0.27162 -0.5761,-0.41048 -0.3856,-0.27966 -0.7611,-0.56553 -1.1378,-0.86416 -0.1871,-0.14821 -0.3696,-0.29358 -0.5545,-0.44649 -0.1864,-0.15403 -0.3704,-0.30928 -0.5545,-0.46808 -0.1828,-0.15761 -0.3595,-0.32017 -0.5401,-0.4825 -0.9031,-0.81159 -1.7795,-1.67679 -2.6285,-2.60688 -0.1699,-0.18602 -0.3437,-0.37813 -0.5113,-0.56891 -0.6171,-0.6993 -1.2315,-1.4415 -1.8436,-2.22522 -0.076,-0.0976 -0.1471,-0.19638 -0.2232,-0.29525 -0.1719,-0.22327 -0.347,-0.44692 -0.5185,-0.67693 -0.8574,-1.15011 -1.7082,-2.38737 -2.5565,-3.70871 -0.3393,-0.52854 -0.6774,-1.07112 -1.0154,-1.62751 -0.169,-0.27819 -0.3354,-0.55736 -0.5041,-0.84255 -0.5043,-0.85289 -1.0109,-1.74117 -1.5123,-2.6573 z" - id="path3154" - inkscape:connector-curvature="0" /> - </g> -</svg> diff --git a/static/img/logos/launchpad.png b/static/img/logos/launchpad.png new file mode 100644 index 00000000..8bc38f2f Binary files /dev/null and b/static/img/logos/launchpad.png differ diff --git a/static/img/logos/phabricator.png b/static/img/logos/phabricator.png new file mode 100644 index 00000000..bcae2ea5 Binary files /dev/null and b/static/img/logos/phabricator.png differ diff --git a/static/img/logos/pypi.png b/static/img/logos/pypi.png new file mode 100644 index 00000000..4d5942ca Binary files /dev/null and b/static/img/logos/pypi.png differ diff --git a/static/img/logos/pypi.svg b/static/img/logos/pypi.svg deleted file mode 100644 index e53853c5..00000000 --- a/static/img/logos/pypi.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="247.808" height="185.85" viewBox="0 0 232.31983 174.23466"><path d="M15.801 114.616l15.555 5.662 15.786-5.746-15.555-5.662zm15.623-12.783l15.556 5.662 15.785-5.746-15.555-5.662z" fill="#f7f7f4" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M31.424 101.833l15.556 5.662v18.282l-15.556-5.661z" fill="#efeeea" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M.178 138.76l15.555 5.663 15.786-5.746-15.556-5.662z" fill="#f7f7f4" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M.178 138.76l15.555 5.663v18.282L.178 157.044z" fill="#efeeea" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M.178 112.76l15.555 5.663 15.786-5.746-15.556-5.662z" fill="#f7f7f4" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M15.733 118.423v18.282l15.786-5.745v-18.283z" fill="#fff" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M.178 112.76l15.555 5.663v18.282L.178 131.044z" fill="#efeeea" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M15.985 97.209l-.025.031a2.783 2.783 0 0 0-2.758 2.781 2.783 2.783 0 0 0 .053.532L1.51 114.937l7.647 9.364-3.87-9.364 9.985-12.228a2.783 2.783 0 0 0 .715.096 2.783 2.783 0 0 0 .715-.094l5.314 6.508 5.373 1.955-8.672-10.621a2.783 2.783 0 0 0 .051-.531 2.783 2.783 0 0 0-2.756-2.782l-.025-.03zm2.135-7.289a2.136 2.136 0 1 0-4.27 0v3.265a2.136 2.136 0 0 0 4.27 0V89.92zm-.98-.002v3.265a1.155 1.155 0 0 1-2.31 0v-3.265a1.154 1.154 0 1 1 2.31 0zm.98-11.211a2.136 2.136 0 1 0-4.27 0v3.266a2.136 2.136 0 0 0 4.27 0v-3.266zm-.98-.002v3.266a1.155 1.155 0 0 1-2.31 0v-3.266a1.154 1.154 0 1 1 2.31 0z" fill="#646464"/><path d="M16.505 82.697v6.498a.518.518 0 1 1-1.04 0v-6.498a.518.518 0 1 1 1.04 0zm0 11.213v6.498a.518.518 0 1 1-1.04 0V93.91a.518.518 0 1 1 1.04 0zm0-22.463v6.498a.518.518 0 1 1-1.04 0v-6.498a.518.518 0 1 1 1.04 0z" fill="#646464"/><path d="M15.8 144.442l15.556 5.662v18.283l-15.555-5.662z" fill="#efeeea" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M15.8 125.978l15.556 5.662 15.786-5.746-15.555-5.661z" fill="#f7f7f4" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M15.8 125.978l15.556 5.662v18.283l-15.555-5.662z" fill="#efeeea" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M93.85 138.741v18.283l15.785-5.745v-18.283z" fill="#fff" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M78.226 144.423v18.282l15.786-5.745v-18.283z" fill="#ffd242" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M91.151 148.88a2.617 3.737 35 0 1-3.032 4.33 2.617 3.737 35 0 1-3.031-2.122 2.617 3.737 35 0 1 3.031-4.33 2.617 3.737 35 0 1 3.032 2.123z" fill="#fff"/><path d="M62.603 150.104v18.283l15.786-5.746v-18.283z" fill="#ffd242" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M46.98 155.785v18.283l15.785-5.746V150.04z" fill="#fff" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M31.424 150.123l15.556 5.662v18.283l-15.556-5.662z" fill="#efeeea" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M93.85 120.278v18.282l15.785-5.745v-18.283z" fill="#ffd242" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M78.294 96.152l15.556 5.662 15.785-5.746-15.555-5.662z" fill="#ffc91d" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M93.85 101.814v18.282l15.785-5.745V96.068zm-15.624 24.145v18.282l15.786-5.745v-18.283z" fill="#ffd242" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M78.226 107.495v18.282l15.786-5.745v-18.283z" fill="#3775a9" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M62.671 83.369l15.555 5.662 15.786-5.746-15.555-5.661z" fill="#2f6491" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M78.226 89.03v18.283l15.786-5.745V83.285z" fill="#3775a9" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M62.603 131.64v18.283l15.786-5.746v-18.283z" fill="#ffd242" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M62.603 113.176v18.283l15.786-5.746V107.43zM46.98 137.321v18.283l15.785-5.746v-18.282z" fill="#3775a9" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M31.424 131.66l15.556 5.661v18.283l-15.556-5.662zm0-18.465l15.556 5.662 15.785-5.745-15.555-5.662z" fill="#2f6491" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M46.98 118.857v18.283l15.785-5.746v-18.282z" fill="#3775a9" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M31.424 113.195l15.556 5.662v18.283l-15.556-5.662zM47.048 89.05l15.555 5.662 15.786-5.746-15.556-5.661z" fill="#2f6491" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M62.603 94.712v18.283l15.786-5.746V88.966z" fill="#3775a9" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M47.048 89.05l15.555 5.662v18.283l-15.555-5.662z" fill="#2f6491" stroke="#ccc" stroke-width=".355" stroke-linejoin="bevel"/><path d="M71.528 100.584a2.617 3.737 35 0 1-3.032 4.33 2.617 3.737 35 0 1-3.032-2.123 2.617 3.737 35 0 1 3.032-4.33 2.617 3.737 35 0 1 3.032 2.123z" fill="#fff"/><path d="M36.661 38.858c0-9.645-2.75-14.597-8.25-14.868a15.497 15.497 0 0 0-6.405 1.052c-1.659.594-2.776 1.182-3.363 1.776v23.021c3.518 2.208 6.643 3.234 9.367 3.073 5.765-.38 8.651-5.061 8.651-14.054zm6.785.4c0 4.9-1.15 8.967-3.46 12.201-2.576 3.66-6.146 5.546-10.71 5.65-3.441.11-6.986-.97-10.633-3.229v20.924l-5.9-2.105V26.256c.968-1.188 2.213-2.208 3.724-3.073 3.512-2.047 7.78-3.099 12.802-3.15l.084.083c4.59-.058 8.128 1.827 10.613 5.65 2.318 3.505 3.48 7.998 3.48 13.492zM79.508 52.99c0 6.572-.658 11.123-1.975 13.654-1.324 2.53-3.841 4.55-7.56 6.055-3.015 1.188-6.275 1.834-9.774 1.943l-.975-3.718c3.557-.484 6.062-.969 7.515-1.453 2.86-.968 4.822-2.453 5.9-4.441.865-1.62 1.292-4.713 1.292-9.29v-1.537a30.317 30.317 0 0 1-12.686 2.744c-2.905 0-5.468-.91-7.676-2.744-2.48-1.995-3.719-4.525-3.719-7.592V22.053l5.9-2.02v24.719c0 2.64.853 4.674 2.557 6.1 1.705 1.427 3.913 2.112 6.618 2.06 2.705-.058 5.603-1.104 8.683-3.15V20.923h5.9V52.99zm23.035 3.796c-.704.058-1.35.083-1.943.083-3.338 0-5.94-.794-7.8-2.388-1.852-1.595-2.782-3.796-2.782-6.605v-23.24h-4.04v-3.713h4.04v-9.858l5.895-2.098v11.956h6.63v3.712h-6.63v23.08c0 2.214.594 3.783 1.781 4.7 1.02.755 2.64 1.188 4.849 1.297v3.073zm35.727-.485h-5.901V33.525c0-2.317-.543-4.312-1.62-5.978-1.247-1.885-2.977-2.828-5.198-2.828-2.705 0-6.087 1.427-10.148 4.28v27.302h-5.9V1.86l5.9-1.859v24.797c3.77-2.744 7.889-4.119 12.363-4.119 3.124 0 5.655 1.052 7.592 3.15 1.943 2.099 2.911 4.713 2.911 7.838V56.3zm31.362-18.373c0-3.706-.704-6.766-2.105-9.187-1.665-2.95-4.254-4.506-7.753-4.667-6.469.374-9.697 5.01-9.697 13.893 0 4.073.672 7.476 2.027 10.206 1.73 3.48 4.326 5.197 7.786 5.14 6.495-.052 9.742-5.178 9.742-15.385zm6.462.039c0 5.274-1.35 9.664-4.041 13.17-2.963 3.925-7.056 5.894-12.28 5.894-5.177 0-9.212-1.97-12.123-5.894-2.64-3.506-3.958-7.896-3.958-13.17 0-4.958 1.427-9.129 4.28-12.525 3.015-3.602 6.98-5.41 11.88-5.41s8.889 1.808 11.962 5.41c2.853 3.396 4.28 7.567 4.28 12.525zm33.829 18.334h-5.9V32.234c0-2.64-.795-4.7-2.383-6.185-1.588-1.478-3.706-2.195-6.346-2.137-2.802.052-5.468.969-7.999 2.744v29.645h-5.9V25.927c3.395-2.473 6.52-4.087 9.373-4.842 2.692-.704 5.068-1.053 7.115-1.053 1.4 0 2.717.136 3.957.407 2.318.536 4.203 1.53 5.655 2.99 1.62 1.613 2.428 3.55 2.428 5.816V56.3z" fill="#646464"/><path style="line-height:125%" d="M221.391 14.428h1.014V8.07h2.402v-.758h-5.817v.758h2.401v6.358m4.315 0h.866V8.621l1.88 5.807h.964l1.959-5.787v5.787h.945V7.312h-1.25l-2.141 6.097-1.826-6.097h-1.397v7.116" font-weight="400" font-size="15.164" font-family="Bitstream Vera Sans" fill="#646464"/><path style="line-height:125%;-inkscape-font-specification:'Source Sans Pro Semi-Bold'" d="M120.607 82.731h2.988v-6.183h2.679c3.632 0 6.415-1.726 6.415-5.461 0-3.916-2.731-5.204-6.415-5.204h-5.667v16.848zm2.988-8.578v-5.874h2.447c2.447 0 3.71.696 3.71 2.808 0 2.06-1.211 3.066-3.71 3.066h-2.447zm10.502 5.177c0 2.216 1.546 3.71 3.762 3.71 1.494 0 2.782-.747 3.915-1.7h.077l.232 1.391h2.422v-7.496c0-3.53-1.546-5.462-4.714-5.462-2.01 0-3.787.773-5.178 1.649l1.082 1.984c1.107-.67 2.292-1.237 3.555-1.237 1.7 0 2.266 1.133 2.292 2.473-5.178.567-7.445 1.984-7.445 4.689zm2.886-.231c0-1.263 1.133-2.164 4.56-2.602v2.834c-.928.875-1.727 1.39-2.757 1.39-1.056 0-1.803-.489-1.803-1.622zm10.315-2.679c0 4.199 2.654 6.62 6.106 6.62 1.442 0 2.962-.567 4.147-1.623l-1.236-1.88c-.696.566-1.572 1.082-2.602 1.082-1.984 0-3.375-1.675-3.375-4.2 0-2.55 1.417-4.224 3.452-4.224.799 0 1.469.335 2.138.927l1.417-1.88c-.85-.825-2.086-1.469-3.71-1.469-3.374 0-6.337 2.422-6.337 6.647zm12.749 6.311h2.911v-3.22l1.984-2.267 3.246 5.487h3.22l-4.766-7.496 4.328-5.153h-3.246l-4.688 5.822h-.078v-11.36h-2.91V82.73zm12.642-3.401c0 2.216 1.546 3.71 3.761 3.71 1.494 0 2.782-.747 3.916-1.7h.077l.232 1.391h2.421v-7.496c0-3.53-1.545-5.462-4.714-5.462-2.01 0-3.787.773-5.178 1.649l1.082 1.984c1.108-.67 2.293-1.237 3.555-1.237 1.7 0 2.267 1.133 2.293 2.473-5.178.567-7.445 1.984-7.445 4.689zm2.885-.231c0-1.263 1.134-2.164 4.56-2.602v2.834c-.928.875-1.726 1.39-2.757 1.39-1.056 0-1.803-.489-1.803-1.622zm12.763 5.487c0-.593.31-1.16.98-1.675.489.13 1.03.18 1.725.18h1.726c1.443 0 2.241.284 2.241 1.263 0 1.082-1.39 2.035-3.426 2.035-2.01 0-3.246-.67-3.246-1.803zm-2.473.438c0 2.215 2.241 3.297 5.255 3.297 4.122 0 6.75-1.958 6.75-4.456 0-2.19-1.597-3.118-4.637-3.118h-2.241c-1.546 0-2.061-.438-2.061-1.159 0-.567.232-.876.618-1.21a4.665 4.665 0 0 0 1.726.334c2.68 0 4.792-1.494 4.792-4.302 0-.876-.31-1.649-.722-2.138h2.319v-2.19h-4.534a5.7 5.7 0 0 0-1.855-.309c-2.653 0-4.998 1.623-4.998 4.534 0 1.494.799 2.705 1.649 3.35v.102c-.721.515-1.391 1.365-1.391 2.344 0 1.03.49 1.7 1.133 2.113v.103c-1.159.721-1.803 1.649-1.803 2.705zm5.41-8.167c-1.237 0-2.215-.927-2.215-2.55 0-1.597.978-2.499 2.215-2.499 1.236 0 2.19.928 2.19 2.5 0 1.622-.98 2.55-2.19 2.55zm7.597-.437c0 4.173 2.73 6.62 6.234 6.62 1.598 0 3.117-.567 4.328-1.365l-1.004-1.855c-.928.593-1.855.927-2.937.927-2.035 0-3.478-1.288-3.736-3.58h8.038c.077-.31.129-.825.129-1.391 0-3.53-1.804-6.003-5.23-6.003-2.962 0-5.822 2.525-5.822 6.647zm2.86-1.134c.257-2.112 1.545-3.22 3.04-3.22 1.725 0 2.576 1.21 2.576 3.22h-5.616zm-81.124 33.721h2.988V92.16h-2.988v16.848zm6.987 0h2.963v-8.836c1.056-1.03 1.777-1.571 2.885-1.571 1.391 0 1.984.772 1.984 2.86v7.547h2.962v-7.934c0-3.195-1.185-5.024-3.89-5.024-1.726 0-3.014.902-4.147 2.01h-.103l-.206-1.7h-2.448v12.648zm13.668-6.311c0 4.173 2.035 6.62 5.204 6.62 1.365 0 2.653-.747 3.58-1.674h.104l.206 1.365h2.447V90.82h-2.963v4.585l.103 2.035c-.979-.85-1.88-1.39-3.323-1.39-2.756 0-5.358 2.524-5.358 6.646zm3.065-.026c0-2.654 1.314-4.174 2.937-4.174.85 0 1.7.284 2.576 1.057v5.899c-.85.979-1.674 1.417-2.653 1.417-1.83 0-2.86-1.469-2.86-4.2zm11.424.026c0 4.173 2.731 6.62 6.234 6.62 1.598 0 3.118-.567 4.328-1.365l-1.004-1.855c-.928.593-1.855.927-2.937.927-2.035 0-3.478-1.288-3.735-3.58h8.037c.077-.31.129-.825.129-1.391 0-3.53-1.803-6.003-5.23-6.003-2.962 0-5.822 2.525-5.822 6.647zm2.86-1.134c.257-2.112 1.545-3.22 3.04-3.22 1.726 0 2.576 1.21 2.576 3.22h-5.616zm9.225 7.445h3.091l1.34-2.499c.36-.773.747-1.52 1.107-2.241h.103c.438.721.876 1.494 1.288 2.241l1.546 2.5h3.195l-4.02-6.26 3.736-6.39h-3.065l-1.211 2.396c-.31.696-.67 1.443-.98 2.138h-.102a87.248 87.248 0 0 1-1.16-2.138l-1.416-2.396h-3.195l3.761 6.054-4.018 6.595z" font-weight="600" font-family="Source Sans Pro" letter-spacing="0" word-spacing="0" fill="#646464"/></svg> \ No newline at end of file diff --git a/static/img/logos/sourceforge.png b/static/img/logos/sourceforge.png new file mode 100644 index 00000000..c307f271 Binary files /dev/null and b/static/img/logos/sourceforge.png differ diff --git a/swh/web/config.py b/swh/web/config.py index 169b317b..dba7378f 100644 --- a/swh/web/config.py +++ b/swh/web/config.py @@ -1,220 +1,219 @@ # Copyright (C) 2017-2021 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information import os from typing import Any, Dict from swh.core import config from swh.counters import get_counters from swh.indexer.storage import get_indexer_storage from swh.scheduler import get_scheduler from swh.search import get_search from swh.storage import get_storage from swh.vault import get_vault from swh.web import settings SWH_WEB_INTERNAL_SERVER_NAME = "archive.internal.softwareheritage.org" STAGING_SERVER_NAMES = [ "webapp.staging.swh.network", "webapp.internal.staging.swh.network", ] ORIGIN_VISIT_TYPES = [ "cran", "deb", "deposit", "ftp", "hg", "git", "nixguix", "npm", "pypi", "svn", "tar", ] SETTINGS_DIR = os.path.dirname(settings.__file__) DEFAULT_CONFIG = { "allowed_hosts": ("list", []), "storage": ( "dict", {"cls": "remote", "url": "http://127.0.0.1:5002/", "timeout": 10,}, ), "indexer_storage": ( "dict", {"cls": "remote", "url": "http://127.0.0.1:5007/", "timeout": 1,}, ), "counters": ( "dict", {"cls": "remote", "url": "http://127.0.0.1:5011/", "timeout": 1,}, ), "search": ( "dict", {"cls": "remote", "url": "http://127.0.0.1:5010/", "timeout": 10,}, ), "search_config": ( "dict", {"backend": "swh-indexer-storage", "enable_ql": False}, # or "swh-search" ), "log_dir": ("string", "/tmp/swh/log"), "debug": ("bool", False), "serve_assets": ("bool", False), "host": ("string", "127.0.0.1"), "port": ("int", 5004), "secret_key": ("string", "development key"), # do not display code highlighting for content > 1MB "content_display_max_size": ("int", 5 * 1024 * 1024), "snapshot_content_max_size": ("int", 1000), "throttling": ( "dict", { "cache_uri": None, # production: memcached as cache (127.0.0.1:11211) # development: in-memory cache so None "scopes": { "swh_api": { "limiter_rate": {"default": "120/h"}, "exempted_networks": ["127.0.0.0/8"], }, "swh_api_origin_search": { "limiter_rate": {"default": "10/m"}, "exempted_networks": ["127.0.0.0/8"], }, "swh_vault_cooking": { "limiter_rate": {"default": "120/h", "GET": "60/m"}, "exempted_networks": ["127.0.0.0/8"], }, "swh_save_origin": { "limiter_rate": {"default": "120/h", "POST": "10/h"}, "exempted_networks": ["127.0.0.0/8"], }, "swh_api_origin_visit_latest": { "limiter_rate": {"default": "700/m"}, "exempted_networks": ["127.0.0.0/8"], }, }, }, ), "vault": ("dict", {"cls": "remote", "args": {"url": "http://127.0.0.1:5005/",}}), "scheduler": ("dict", {"cls": "remote", "url": "http://127.0.0.1:5008/"}), "development_db": ("string", os.path.join(SETTINGS_DIR, "db.sqlite3")), "test_db": ("string", os.path.join(SETTINGS_DIR, "testdb.sqlite3")), "production_db": ("dict", {"name": "swh-web"}), "deposit": ( "dict", { "private_api_url": "https://deposit.softwareheritage.org/1/private/", "private_api_user": "swhworker", "private_api_password": "some-password", }, ), - "coverage_count_origins": ("bool", False), "e2e_tests_mode": ("bool", False), "es_workers_index_url": ("string", ""), "history_counters_url": ( "string", ( "http://counters1.internal.softwareheritage.org:5011" "/counters_history/history.json" ), ), "client_config": ("dict", {}), "keycloak": ("dict", {"server_url": "", "realm_name": ""}), "graph": ( "dict", {"server_url": "http://graph.internal.softwareheritage.org:5009/graph/"}, ), "status": ( "dict", { "server_url": "https://status.softwareheritage.org/", "json_path": "1.0/status/578e5eddcdc0cc7951000520", }, ), "counters_backend": ("string", "swh-storage"), # or "swh-counters" "staging_server_names": ("list", STAGING_SERVER_NAMES), "instance_name": ("str", "archive-test.softwareheritage.org"), } swhweb_config: Dict[str, Any] = {} def get_config(config_file="web/web"): """Read the configuration file `config_file`. If an environment variable SWH_CONFIG_FILENAME is defined, this takes precedence over the config_file parameter. In any case, update the app with parameters (secret_key, conf) and return the parsed configuration as a dict. If no configuration file is provided, return a default configuration. """ if not swhweb_config: config_filename = os.environ.get("SWH_CONFIG_FILENAME") if config_filename: config_file = config_filename cfg = config.load_named_config(config_file, DEFAULT_CONFIG) swhweb_config.update(cfg) config.prepare_folders(swhweb_config, "log_dir") if swhweb_config.get("search"): swhweb_config["search"] = get_search(**swhweb_config["search"]) else: swhweb_config["search"] = None swhweb_config["storage"] = get_storage(**swhweb_config["storage"]) swhweb_config["vault"] = get_vault(**swhweb_config["vault"]) swhweb_config["indexer_storage"] = get_indexer_storage( **swhweb_config["indexer_storage"] ) swhweb_config["scheduler"] = get_scheduler(**swhweb_config["scheduler"]) swhweb_config["counters"] = get_counters(**swhweb_config["counters"]) return swhweb_config def search(): """Return the current application's search. """ return get_config()["search"] def storage(): """Return the current application's storage. """ return get_config()["storage"] def vault(): """Return the current application's vault. """ return get_config()["vault"] def indexer_storage(): """Return the current application's indexer storage. """ return get_config()["indexer_storage"] def scheduler(): """Return the current application's scheduler. """ return get_config()["scheduler"] def counters(): """Return the current application's counters. """ return get_config()["counters"] diff --git a/swh/web/misc/coverage.py b/swh/web/misc/coverage.py index c42c4aae..b4b84234 100644 --- a/swh/web/misc/coverage.py +++ b/swh/web/misc/coverage.py @@ -1,170 +1,376 @@ -# Copyright (C) 2018-2019 The Software Heritage developers +# Copyright (C) 2018-2021 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information +from collections import Counter, defaultdict +from functools import lru_cache +from typing import Dict, List, Tuple +from urllib.parse import urlparse + +import sentry_sdk + from django.conf.urls import url from django.shortcuts import render from django.views.decorators.clickjacking import xframe_options_exempt -from swh.web.config import get_config - -# Current coverage list of the archive -# TODO: Retrieve that list dynamically instead of hardcoding it -_code_providers = [ - { - "provider_id": "bitbucket", - "provider_url": "https://bitbucket.org/", - "provider_logo": "img/logos/bitbucket.png", - "provider_info": "public repositories from Bitbucket " - "(continuously archived)", - "origin_url_regexp": "^https://bitbucket.org/", - "origin_types": "repositories", - }, - { - "provider_id": "cran", - "provider_url": "https://cran.r-project.org/", - "provider_logo": "img/logos/cran.svg", - "provider_info": "source packages from The Comprehensive R Archive " - "Network (continuously archived)", - "origin_url_regexp": "^https://cran.r-project.org/", - "origin_types": "packages", - }, - { - "provider_id": "debian", - "provider_url": "https://www.debian.org/", - "provider_logo": "img/logos/debian.png", - "provider_info": "source packages from the Debian distribution " - "(continuously archived)", - "origin_url_regexp": "^deb://", - "origin_types": "packages", - }, - { - "provider_id": "framagit", - "provider_url": "https://framagit.org/", - "provider_logo": "img/logos/framagit.png", - "provider_info": "public repositories from Framagit " "(continuously archived)", - "origin_url_regexp": "^https://framagit.org/", - "origin_types": "repositories", - }, - { - "provider_id": "github", - "provider_url": "https://github.com", - "provider_logo": "img/logos/github.png", - "provider_info": "public repositories from GitHub " "(continuously archived)", - "origin_url_regexp": "^https://github.com/", - "origin_types": "repositories", - }, - { - "provider_id": "gitlab", - "provider_url": "https://gitlab.com", - "provider_logo": "img/logos/gitlab.svg", - "provider_info": "public repositories from GitLab " "(continuously archived)", - "origin_url_regexp": "^https://gitlab.com/", - "origin_types": "repositories", - }, - { - "provider_id": "gitorious", - "provider_url": "https://gitorious.org/", - "provider_logo": "img/logos/gitorious.png", - "provider_info": "public repositories from the former Gitorious code " - "hosting service", - "origin_url_regexp": "^https://gitorious.org/", - "origin_types": "repositories", - }, - { - "provider_id": "googlecode", - "provider_url": "https://code.google.com/archive/", - "provider_logo": "img/logos/googlecode.png", - "provider_info": "public repositories from the former Google Code " - "project hosting service", - "origin_url_regexp": "^http.*.googlecode.com/", - "origin_types": "repositories", - }, - { - "provider_id": "gnu", - "provider_url": "https://www.gnu.org", - "provider_logo": "img/logos/gnu.png", - "provider_info": "releases from the GNU project (as of August 2015)", - "origin_url_regexp": "^rsync://ftp.gnu.org/", - "origin_types": "releases", - }, - { - "provider_id": "guix", - "provider_url": "https://guix.gnu.org/", - "provider_logo": "img/logos/guix.svg", - "provider_info": "source code tarballs used to build the Guix package " - "collection", - "origin_url_regexp": "^https://guix.gnu.org/", - "origin_types": "tarballs", - }, - { - "provider_id": "hal", - "provider_url": "https://hal.archives-ouvertes.fr/", - "provider_logo": "img/logos/hal.png", - "provider_info": "scientific software source code deposited in the " - "open archive HAL", - "origin_url_regexp": "^https://hal.archives-ouvertes.fr/", - "origin_types": "deposits", - }, - { - "provider_id": "inria", - "provider_url": "https://gitlab.inria.fr", - "provider_logo": "img/logos/inria.jpg", - "provider_info": "public repositories from Inria GitLab " - "(continuously archived)", - "origin_url_regexp": "^https://gitlab.inria.fr/", - "origin_types": "repositories", - }, - { - "provider_id": "ipol", - "provider_url": "https://www.ipol.im/", - "provider_logo": "img/logos/ipol.png", - "provider_info": "software artifacts associated to the articles " - "IPOL publishes", - "origin_url_regexp": "^https://doi.org/10.5201/ipol", - "origin_types": "tarballs", - }, - { - "provider_id": "npm", - "provider_url": "https://www.npmjs.com/", - "provider_logo": "img/logos/npm.png", - "provider_info": "public packages from the package registry for " - "javascript (continuously archived)", - "origin_url_regexp": "^https://www.npmjs.com/", - "origin_types": "packages", - }, - { - "provider_id": "nixos", - "provider_url": "https://nixos.org/", - "provider_logo": "img/logos/nixos.png", - "provider_info": "source code tarballs used to build the Nix package " - "collection", - "origin_url_regexp": "^https://nix-community.github.io/nixpkgs-swh", - "origin_types": "tarballs", - }, - { - "provider_id": "pypi", - "provider_url": "https://pypi.org", - "provider_logo": "img/logos/pypi.svg", - "provider_info": "source packages from the Python Packaging Index " - "(continuously archived)", - "origin_url_regexp": "^https://pypi.org/", - "origin_types": "packages", - }, -] +from swh.scheduler.model import SchedulerMetrics +from swh.web.common import archive +from swh.web.common.utils import get_deposits_list, reverse +from swh.web.config import scheduler + +_swh_arch_overview_doc = ( + "https://docs.softwareheritage.org/devel/architecture/overview.html" +) + +# Current coverage list of the archive in a high level overview fashion, +# categorized as follow: +# - listed origins: origins discovered using a swh lister +# - legacy: origins where public hosting service has closed +# - deposited: origins coming from swh-deposit +# +# TODO: Store that list in a database table somewhere (swh-scheduler, swh-storage ?) +# and retrieve it dynamically +listed_origins = { + "info": ( + "These software origins get continuously discovered and archived using " + f'the <a href="{_swh_arch_overview_doc}#listers" target="_blank" ' + 'rel="noopener noreferrer">listers</a> implemented by Software Heritage.' + ), + "origins": [ + { + "type": "bitbucket", + "info_url": "https://bitbucket.org", + "info": "public repositories from Bitbucket", + "search_pattern": "https://bitbucket.org/", + }, + { + "type": "cgit", + "info_url": "https://git.zx2c4.com/cgit/about", + "info": "public repositories from cgit instances", + "search_pattern": "cgit", + }, + { + "type": "CRAN", + "info_url": "https://cran.r-project.org", + "info": "source packages from The Comprehensive R Archive Network", + "search_pattern": "https://cran.r-project.org/", + }, + { + "type": "debian", + "info_url": "https://www.debian.org", + "info": "source packages from the Debian distribution", + "search_pattern": "deb://", + }, + { + "type": "gitea", + "info_url": "https://gitea.io", + "info": "public repositories from Gitea instances", + "search_pattern": "gitea", + }, + { + "type": "github", + "info_url": "https://github.com", + "info": "public repositories from GitHub", + "search_pattern": "https://github.com/", + }, + { + "type": "gitlab", + "info_url": "https://gitlab.com", + "info": "public repositories from multiple GitLab instances", + "search_pattern": "gitlab", + }, + { + "type": "guix", + "info_url": "https://guix.gnu.org", + "info": "source code tarballs used to build the Guix package collection", + "visit_types": ["nixguix"], + "search_pattern": "https://guix.gnu.org/sources.json", + }, + { + "type": "GNU", + "info_url": "https://www.gnu.org", + "info": "releases from the GNU project (as of August 2015)", + "search_pattern": "gnu", + }, + { + "type": "launchpad", + "info_url": "https://launchpad.net", + "logo": "img/logos/launchpad.png", + "info": "public repositories from Launchpad", + "search_pattern": "https://git.launchpad.net/", + }, + { + "type": "nixos", + "info_url": "https://nixos.org", + "info": "source code tarballs used to build the Nix package collection", + "visit_types": ["nixguix"], + "search_pattern": ( + "https://nix-community.github.io/nixpkgs-swh/sources-unstable.json" + ), + }, + { + "type": "npm", + "info_url": "https://www.npmjs.com", + "info": "public packages from the package registry for javascript", + "search_pattern": "https://www.npmjs.com", + }, + # apart our forge, most phabricator origins have not been archived + # while they have been listed so do not display those type of origins + # until new listing processes have been executed and origins loaded + # + # { + # "type": "phabricator", + # "info_url": "https://www.phacility.com/phabricator", + # "info": "public repositories from multiple Phabricator instances", + # "search_pattern": "phabricator", + # }, + { + "type": "pypi", + "info_url": "https://pypi.org", + "info": "source packages from the Python Package Index", + "search_pattern": "https://pypi.org", + }, + { + "type": "sourceforge", + "info_url": "https://sourceforge.net", + "info": "public repositories from SourceForge", + "search_pattern": "code.sf.net", + }, + ], +} + +legacy_origins = { + "info": ( + "Discontinued hosting services. Those origins have been archived " + "by Software Heritage." + ), + "origins": [ + { + "type": "gitorious", + "info_url": "https://en.wikipedia.org/wiki/Gitorious", + "info": ( + "public repositories from the former Gitorious code hosting service" + ), + "visit_types": ["git"], + "search_pattern": "https://gitorious.org", + "count": "122,014", + }, + { + "type": "googlecode", + "info_url": "https://code.google.com/archive", + "info": ( + "public repositories from the former Google Code project " + "hosting service" + ), + "visit_types": ["git", "hg", "svn"], + "search_pattern": "googlecode.com", + "count": "790,026", + }, + ], +} + +deposited_origins = { + "info": ( + "These origins are directly pushed into the archive by trusted partners " + f'using the <a href="{_swh_arch_overview_doc}#deposit" target="_blank" ' + 'rel="noopener noreferrer">deposit</a> service of Software Heritage.' + ), + "origins": [ + { + "type": "elife", + "info_url": "https://elifesciences.org", + "info": ( + "research software source code associated to the articles " + "eLife publishes" + ), + "search_pattern": "elife.stencila.io", + "visit_types": ["deposit"], + }, + { + "type": "hal", + "info_url": "https://hal.archives-ouvertes.fr", + "info": "scientific software source code deposited in the open archive HAL", + "visit_types": ["deposit"], + "search_pattern": "hal.archives-ouvertes.fr", + }, + { + "type": "ipol", + "info_url": "https://www.ipol.im", + "info": "software artifacts associated to the articles IPOL publishes", + "visit_types": ["deposit"], + "search_pattern": "doi.org/10.5201", + }, + ], +} + + +@lru_cache() +def _get_listers_metrics() -> Dict[str, List[Tuple[str, SchedulerMetrics]]]: + """Returns scheduler metrics in the following mapping: + Dict[lister_name, List[Tuple[instance_name, SchedulerMetrics]]] + as a lister instance has one SchedulerMetrics object per visit type. + """ + listers_metrics = defaultdict(list) + try: + listers = scheduler().get_listers() + scheduler_metrics = scheduler().get_metrics() + for lister in listers: + for metrics in filter( + lambda m: m.lister_id == lister.id, scheduler_metrics + ): + listers_metrics[lister.name].append((lister.instance_name, metrics)) + except Exception as e: + sentry_sdk.capture_exception(e) + return listers_metrics + + +@lru_cache() +def _get_deposits_netloc_counts() -> Counter: + """Return deposit counts per origin url network location. + """ + + def _process_origin_url(origin_url): + parsed_url = urlparse(origin_url) + netloc = parsed_url.netloc + # special treatment for doi.org netloc as it is not specific enough + # for origins mapping + if parsed_url.netloc == "doi.org": + netloc += "/" + parsed_url.path.split("/")[1] + return netloc + + netlocs = [] + try: + deposits = get_deposits_list() + netlocs = [ + _process_origin_url(d["origin_url"]) + for d in deposits + if d["status"] == "done" + ] + except Exception as e: + sentry_sdk.capture_exception(e) + return Counter(netlocs) + + +@lru_cache() +def _get_nixguix_origins_count(origin_url: str) -> int: + """Returns number of archived tarballs for NixOS, aka the number + of branches in a dedicated origin in the archive. + """ + snapshot = archive.lookup_latest_origin_snapshot(origin_url) + if snapshot: + snapshot_sizes = archive.lookup_snapshot_sizes(snapshot["id"]) + return snapshot_sizes["revision"] + else: + return 0 + + +def _search_url(query: str, visit_type: str) -> str: + return reverse( + "browse-search", + query_params={ + "q": query, + "visit_type": visit_type, + "with_visit": "true", + "with_content": "true", + }, + ) @xframe_options_exempt def _swh_coverage(request): - count_origins = get_config()["coverage_count_origins"] + listers_metrics = _get_listers_metrics() + for origins in listed_origins["origins"]: + origins["instances"] = {} + origins_type = origins["type"] + + # special processing for nixos/guix origins as there is no + # scheduler metrics for those + if origins_type in ("nixos", "guix"): + count = _get_nixguix_origins_count(origins["search_pattern"]) + origins["count"] = count + origins["instances"][origins_type] = {"nixguix": {"count": count}} + + if origins_type not in listers_metrics: + continue + + count = sum( + [metrics.origins_known for _, metrics in listers_metrics[origins_type]] + ) + count_never_visited = sum( + [ + metrics.origins_never_visited + for _, metrics in listers_metrics[origins_type] + ] + ) + # CRAN origins are currently marked as not visited while they have been + if origins_type != "CRAN": + count -= count_never_visited + + origins["count"] = f"{count:,}" + origins["instances"] = defaultdict(dict) + for instance, metrics in listers_metrics[origins_type]: + # not yet in production + if metrics.visit_type in ("bzr", "cvs"): + continue + origins["instances"][instance].update( + { + metrics.visit_type: { + "count": metrics.origins_known - metrics.origins_never_visited + } + } + ) + origins["visit_types"] = list( + set(origins["instances"][instance].keys()) + | set(origins.get("visit_types", [])) + ) + + if origins_type == "CRAN": + origins["instances"]["cran"]["cran"] = {"count": origins["count"]} + + # defaultdict cannot be iterated in django template + origins["instances"] = dict(origins["instances"]) + + for origins in listed_origins["origins"]: + instances = origins["instances"] + nb_instances = len(instances) + for instance_name, visit_types in instances.items(): + for visit_type in visit_types: + if nb_instances > 1: + search_pattern = instance_name + else: + search_pattern = origins["search_pattern"] + search_url = _search_url(search_pattern, visit_type) + visit_types[visit_type]["search_url"] = search_url + + for origins in legacy_origins["origins"]: + origins["search_urls"] = {} + for visit_type in origins["visit_types"]: + origins["search_urls"][visit_type] = _search_url( + origins["search_pattern"], visit_type + ) + + deposits_counts = _get_deposits_netloc_counts() + for origins in deposited_origins["origins"]: + if origins["search_pattern"] in deposits_counts: + origins["count"] = f"{deposits_counts[origins['search_pattern']]:,}" + origins["search_urls"] = { + "deposit": _search_url(origins["search_pattern"], "deposit") + } + return render( request, "misc/coverage.html", - {"providers": _code_providers, "count_origins": count_origins}, + { + "origins": { + "Regular crawling": listed_origins, + "Discontinued hosting": legacy_origins, + "On demand archival": deposited_origins, + } + }, ) urlpatterns = [ url(r"^coverage/$", _swh_coverage, name="swh-coverage"), ] diff --git a/swh/web/templates/homepage.html b/swh/web/templates/homepage.html index caa259a6..d49f8411 100644 --- a/swh/web/templates/homepage.html +++ b/swh/web/templates/homepage.html @@ -1,117 +1,113 @@ {% extends "layout.html" %} {% comment %} Copyright (C) 2017-2020 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information {% endcomment %} {% load static %} {% load render_bundle from webpack_loader %} {% block header %} {% render_bundle 'browse' %} {% endblock %} {% block title %}Welcome to the Software Heritage archive{% endblock %} {% block navbar-content %} <h4>Welcome to the Software Heritage archive</h4> {% endblock %} {% block content %} <div class="p-3 swh-search-box swh-background-gray"> <h4>Search</h4> {% include "includes/origin-search-form.html" %} </div> <p class="text-right"> ... or check our <a id="swh-web-api-link" style="color: #e20026;" href="{% url 'api-1-homepage' %}"> <i style="color: #e20026;" class="nav-icon mdi mdi-24px mdi-cogs"></i>Web API </a> </p> <div class="p-3"> <h4>Overview</h4> <p> The long term goal of the Software Heritage initiative is to <strong>collect</strong> all publicly available software in source code form together with its development history, replicate it massively to ensure its <strong>preservation</strong>, and <strong>share</strong> it with everyone who needs it. The Software Heritage archive is growing over time as we crawl new source code from software projects and development forges. </p> </div> <div class="p-3"> <h4>Content</h4> -<p> - A significant amount of source code has already been ingested in the Software Heritage - archive. It currently includes: -</p> <iframe class="swh-coverage-list" src="{% url 'swh-coverage' %}"></iframe> </div> <div class="p-3"> <h4>Size</h4> <p> As of today the archive already contains and keeps safe for you the following amount of objects: <div class="row"> <div class="col-md-4 text-center"> <h5>Source files</h5> <span id="swh-content-count" class="swh-counter">0</span> <div id="swh-content-count-history" class="d3-wrapper swh-counter-history"></div> </div> <div class="col-md-4 swh-counter-container text-center"> <h5>Commits</h5> <span id="swh-revision-count" class="swh-counter">0</span> <div id="swh-revision-count-history" class="d3-wrapper swh-counter-history"></div> </div> <div class="col-md-4 swh-counter-container text-center"> <h5>Projects</h5> <span id="swh-origin-count" class="swh-counter">0</span> <div id="swh-origin-count-history" class="d3-wrapper swh-counter-history"></div> </div> </div> <div class="row mt-3"> <div class="col-md-4 text-center"> <h5>Directories</h5> <span id="swh-directory-count" class="swh-counter">0</span> </div> <div class="col-md-4 swh-counter-container text-center"> <h5>Authors</h5> <span id="swh-person-count" class="swh-counter">0</span> </div> <div class="col-md-4 swh-counter-container text-center"> <h5>Releases</h5> <span id="swh-release-count" class="swh-counter">0</span> </div> </div> <p class="mt-3" style="font-size: 13px"> Note: the counters and graphs above are based on heuristics that might not reflect the exact size of the archive. While the long-term trends shown and ballpark figures are reliable, individual point-in-time values might not be. </p> </p> </div> <script> swh.webapp.initHomePage(); </script> {% endblock %} diff --git a/swh/web/templates/misc/coverage.html b/swh/web/templates/misc/coverage.html index d6171e13..5a6c9658 100644 --- a/swh/web/templates/misc/coverage.html +++ b/swh/web/templates/misc/coverage.html @@ -1,91 +1,151 @@ {% comment %} -Copyright (C) 2015-2019 The Software Heritage developers +Copyright (C) 2015-2021 The Software Heritage developers See the AUTHORS file at the top-level directory of this distribution License: GNU Affero General Public License version 3, or any later version See top-level LICENSE file for more information {% endcomment %} <!DOCTYPE html> {% load js_reverse %} {% load static %} {% load render_bundle from webpack_loader %} <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>Software Heritage archive coverage</title> {% render_bundle 'vendors' %} {% render_bundle 'webapp' %} <script> /* @licstart The following is the entire license notice for the JavaScript code in this page. -Copyright (C) 2015-2019 The Software Heritage developers +Copyright (C) 2015-2021 The Software Heritage developers This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. @licend The above is the entire license notice for the JavaScript code in this page. */ </script> <script src="{% url 'js_reverse' %}" type="text/javascript"></script> <base target="_parent"> </head> <body style="padding-bottom: 0;"> <div class="wrapper" style="margin-left: 0;" data-iframe-height> <div class="content"> <div class="container-fluid"> - <div class="row"> - {% for provider in providers %} - <div class="col-md-2 swh-coverage-col"> - <div class="card swh-coverage" id="{{ provider.provider_id }}" title="{{ provider.provider_info }}"> - <a href="{{ provider.provider_url }}"> - <img class="card-img-top swh-coverage-logo" src="{% static provider.provider_logo %}"> - </a> - <div class="text-center swh-coverage-origin-count"></div> + <p> + A significant amount of source code has already been ingested in the Software Heritage + archive. It notably includes the following software origins. + </p> + {% for origins_type, origins_data in origins.items %} + <h5>{{ origins_type }}</h5> + <p>{{ origins_data.info | safe }}</p> + <div class="row"> + {% for origins in origins_data.origins %} + <div class="col-md-4 swh-coverage-col"> + <div class="card swh-coverage" id="{{ origins.type }}" title="{{ origins.info }}"> + <a href="{{ origins.info_url }}" target="_blank" rel="noopener noreferrer"> + {% with 'img/logos/'|add:origins.type.lower|add:'.png' as png_logo %} + <img class="card-img-top swh-coverage-logo" src="{% static png_logo %}" + alt="{{ origins.type }}"> + {% endwith %} + </a> + <div class="card-header swh-coverage-header"> + <a class="collapsed d-block" data-toggle="collapse" + href="#swh-coverage-info-{{ origins_type.lower|cut:' ' }}" + aria-expanded="true" aria-controls="swh-coverage-info-{{ origins_type.lower|cut:' ' }}" + id="heading-collapsed" + title="click to expand or collapse detailed information about software origins"> + <i class="swh-coverage-chevron mdi mdi-24px mdi-chevron-down"></i> + <div class="text-center" style="font-size: 120%"> + {% if "count" in origins %} + {{ origins.count }} origins + {% else %} + <br/> + {% endif %} + </div> + </a> + </div> + <div id="swh-coverage-info-{{ origins_type.lower|cut:' ' }}" class="collapse" + aria-labelledby="heading-collapsed"> + <div class="card-body text-center swh-coverage-info-body"> + <table style="width: 100%"> + {% if "instances" in origins %} + <thead> + <tr> + <th>instance</th> + <th>type</th> + <th>count</th> + <th>search</th> + </tr> + </thead> + <tbody> + {% for instance, visit_types in origins.instances.items %} + {% for visit_type, data in visit_types.items %} + {% if data.count %} + <tr> + <td>{{ instance }}</td> + <td>{{ visit_type }}</td> + <td>{{ data.count }}</td> + <td> + <a href="{{ data.search_url }}" target="_blank" rel="noopener noreferrer"> + <i class="mdi mdi-magnify"></i> + </a> + </td> + </tr> + {% endif %} + {% endfor %} + {% endfor %} + </tbody> + {% else %} + <thead> + <tr> + <th>instance</th> + <th>type</th> + <th>search</th> + </tr> + </thead> + <tbody> + {% for visit_type, search_url in origins.search_urls.items %} + <tr> + <td>{{ origins.type }}</td> + <td>{{ visit_type }}</td> + <td> + <a href="{{ search_url }}" target="_blank" rel="noopener noreferrer"> + <i class="mdi mdi-magnify"></i> + </a> + </td> + </tr> + {% endfor %} + </tbody> + {% endif %} + </table> + </div> + </div> + </div> </div> - </div> - {% endfor %} - </div> + {% endfor %} + </div> + {% endfor %} </div> </div> </div> <a href="{% url 'jslicenses' %}" rel="jslicense" style="display: none;">JavaScript license information</a> </body> - {% if count_origins %} - <script> - $.ajax({ - url: Urls.swh_coverage_count(), - dataType: 'json', - success: function (data) { - for (var i = 0 ; i < data.length; ++i) { - var origin_count = data[i].origin_count; - var provider_id = data[i].provider_id; - var origin_types = data[i].origin_types; - if (origin_count < 0) { - $('.swh-coverage-origin-count').text(''); - break; - } else { - var text = origin_count.toLocaleString() + ' ' + origin_types; - $('#'+provider_id + ' .swh-coverage-origin-count').text(text); - } - } - } - }); - </script> - {% endif %} </html> diff --git a/swh/web/tests/misc/test_coverage.py b/swh/web/tests/misc/test_coverage.py new file mode 100644 index 00000000..1de2b2c7 --- /dev/null +++ b/swh/web/tests/misc/test_coverage.py @@ -0,0 +1,133 @@ +# Copyright (C) 2021 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU Affero General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from datetime import datetime, timezone +from itertools import chain +import os +from random import choice, randint +import uuid + +import pytest + +from django.conf import settings +from django.utils.html import escape + +from swh.scheduler.model import LastVisitStatus, ListedOrigin, OriginVisitStats +from swh.web.common.utils import reverse +from swh.web.misc.coverage import ( + _get_deposits_netloc_counts, + _get_listers_metrics, + deposited_origins, + legacy_origins, + listed_origins, +) +from swh.web.tests.django_asserts import assert_contains +from swh.web.tests.utils import check_html_get_response + + +@pytest.fixture(autouse=True) +def clear_lru_caches(): + _get_listers_metrics.cache_clear() + _get_deposits_netloc_counts.cache_clear() + + +def test_coverage_view_no_metrics(client): + """ + Check coverage view can be rendered when scheduler metrics and deposits + data are not available. + """ + url = reverse("swh-coverage") + check_html_get_response( + client, url, status_code=200, template_used="misc/coverage.html" + ) + + +def test_coverage_view_with_metrics(client, swh_scheduler, mocker): + """ + Generate some sample scheduler metrics and some sample deposits + that will be consumed by the archive coverage view, then check + the HTML page gets rendered without errors. + """ + mocker.patch( + "swh.web.misc.coverage._get_nixguix_origins_count" + ).return_value = 30095 + listers = [] + for origins in listed_origins["origins"]: + # create some instances for each lister + for instance in range(randint(1, 5)): + lister = swh_scheduler.get_or_create_lister( + origins["type"], f"instance-{instance}" + ) + listers.append(lister) + # record some sample listed origins + _origins = [] + origin_visit_stats = [] + for i in range(randint(3, 10)): + url = str(uuid.uuid4()) + visit_type = choice(["git", "hg", "svn"]) + _origins.append( + ListedOrigin( + lister_id=lister.id, + url=url, + visit_type=visit_type, + extra_loader_arguments={}, + ) + ) + # set origin visit stats to some origins + if i % 2 == 0: + now = datetime.now(tz=timezone.utc) + origin_visit_stats.append( + OriginVisitStats( + url=url, + visit_type=visit_type, + last_successful=now, + last_visit=now, + last_visit_status=LastVisitStatus.successful, + last_snapshot=os.urandom(20), + ) + ) + # send origins data to scheduler + swh_scheduler.record_listed_origins(_origins) + swh_scheduler.origin_visit_stats_upsert(origin_visit_stats) + + # compute scheduler metrics + swh_scheduler.update_metrics() + + # add some sample deposits + deposits = [] + for origins in deposited_origins["origins"]: + for _ in range(randint(2, 10)): + deposits.append( + { + "origin_url": f"https://{origins['search_pattern']}/{uuid.uuid4()}", + "status": "done", + } + ) + get_deposits_list = mocker.patch("swh.web.misc.coverage.get_deposits_list") + get_deposits_list.return_value = deposits + + # check view gets rendered without errors + url = reverse("swh-coverage") + resp = check_html_get_response( + client, url, status_code=200, template_used="misc/coverage.html" + ) + + # check logos and origins search links are present in the rendered page + for origins in chain( + listed_origins["origins"], + legacy_origins["origins"], + deposited_origins["origins"], + ): + logo_url = f'{settings.STATIC_URL}img/logos/{origins["type"].lower()}.png' + assert_contains(resp, f'src="{logo_url}"') + + if "instances" in origins: + for visit_types in origins["instances"].values(): + for data in visit_types.values(): + if data["count"]: + assert_contains(resp, f'<a href="{escape(data["search_url"])}"') + else: + for search_url in origins["search_urls"].values(): + assert_contains(resp, f'<a href="{escape(search_url)}"')